﻿using System;
using System.Collections.Generic;
using MapEngine;
using System.Windows;
using GameEngine.Model.Data.implementation;
using GameEngine.Libs;
using System.Xml.Linq;

namespace GameEngine.Model.Data
{
    public class ThingVO<IdType> : IThingVO<IdType>
        where IdType : IComparable<IdType>
    {
        //TODO novo MovingThingVO - retorna uma view consoante o state
        //IDictionary<string, IThingViewVO<IdType>> States { get; set; }
        //string State { get; }
        public IThingVOId<IdType> Id
        {
            get;
            protected set;
        }

        public IViewStateVO State
        {
            get;
            set;
        }

        public Point3d Position
        {
            get;
            set;
        }

        public IThingTypeVOId TypeId
        {
            get;
            protected set;
        }

        public bool MovingWithMouse { get; set; }

        /// <summary>
        /// Where north in map is (0,1)
        /// </summary>
        public Point Direction { get; set; }

        public ThingVO()
        {
        }

        public ThingVO(IThingVOId<IdType> id, IThingTypeVOId typeId)
        {
            //ClassType = "ThingVO";
            this.Id = id;
            TypeId = typeId;
            Position = new Point3d();
            State = IViewVOConstants.DefaultState;
            Direction = new Point(0, -1);
        }

        public virtual string Serialize()
        {
            //return Serializer.Serialize(VO);
            XDocument doc = new XDocument();
            XElement mainNode = new XElement("ThingVO");
            mainNode.SetAttributeValue("Class", GetType());

            {
                XElement node = new XElement("Id", new XAttribute("Class", Id.GetType()));
                node.Add(Id.Serialize());
                mainNode.Add(node);
            }
            {
                XElement node = new XElement("State", new XAttribute("Class", State.GetType()));
                node.Add(new XCData(Serializer.Serialize(State)));
                mainNode.Add(node);
            }
            {
                XElement node = new XElement("Position");
                node.Add(new XCData(Serializer.Serialize(Position)));
                mainNode.Add(node);
            }
            {
                XElement node = new XElement("TypeId",new XAttribute("Class", TypeId.GetType()));
                node.Add(TypeId.Serialize());
                mainNode.Add(node);
            }
            {
                XElement node = new XElement("Direction");
                node.Add(new XCData(Serializer.Serialize(Direction)));
                mainNode.Add(node);
            }
            return mainNode.ToString();
        }

        public virtual void DeSerialize(string serializedString)
        {
            XElement mainNode = XElement.Parse(serializedString);
            foreach (XElement node in mainNode.Nodes())
            {
                switch (node.Name.LocalName)
                {
                    case "State":
                        {
                            var className = node.Attribute("Class").Value;
                            var classType = Type.GetType(className);
                            var instance = Activator.CreateInstance(classType, node.Value) as IViewStateVO;
                            State = instance;
                        }
                        break;
                    case "Id":
                        {
                            var className = node.Attribute("Class").Value;
                            var classType = Type.GetType(className);
                            var instance = Activator.CreateInstance(classType) as IThingVOId<IdType>;
                            instance.DeSerialize(node.Value);
                            Id = instance;
                        }
                        break;
                    case "TypeId":
                        {
                            var className = node.Attribute("Class").Value;
                            var classType = Type.GetType(className);
                            var instance = Activator.CreateInstance(classType) as IThingTypeVOId;
                            instance.DeSerialize(node.Value);
                            TypeId = instance;
                        }
                        break;
                    case "Position":
                        {
                            Position = (Point3d)Serializer.DeSerialize(typeof(Point3d), node.Value);
                        }
                        break;
                    case "Direction":
                        {
                            Direction = (Point)Serializer.DeSerialize(typeof(Point), node.Value);
                        }
                        break;
                }
            }
        }
    }

    public struct ViewStateVO : IViewStateVO
    { 
        string id;
        public string Value { get { return id; } }

        public ViewStateVO(string id)
        {
            this.id = id;
        }
    }

    public class ThingVOId<IdType> : Id<IdType>, IThingVOId<IdType> where IdType : IComparable<IdType>{
        public ThingVOId(IdType id) : base(id) { }
        public ThingVOId() { }
    }

    public class SensingThingVO<IdType> : ThingVO<IdType>, ISensingThingVO<IdType>
        where IdType : IComparable<IdType>
    {

        public SensingThingVO(IThingVOId<IdType> id, IThingTypeVOId typeId) :
            base(id, typeId)
        {
            //ClassType = "SensingThingVO";
        }
    }

    public class MovingThingVO<IdType> : ThingVO<IdType>, IMovingThingVO<IdType>
        where IdType : IComparable<IdType>
    {
        public Point? Destination { get; set; }

        public MovingThingVO()
        {
        }

        public MovingThingVO(IThingVOId<IdType> id, IThingTypeVOId typeId) :
            base(id, typeId)
        {
            //ClassType = "MovingThingVO";
        }
    }

    public class ThinkingThingVO<IdType> : MovingThingVO<IdType>, IThinkingThingVO<IdType>
        where IdType : IComparable<IdType>
    {
        //Memory?
        public NeuralNetwork Brain { get; set; }

        public ThinkingThingVO(IThingVOId<IdType> id, IThingTypeVOId typeId) :
            base(id, typeId)
        {
            Brain = new NeuralNetwork(1, new int[] { 0 });
            //ClassType = "ThinkingThingVO";
        }
    }

    /*
    public class ItemVOParameters {
        public List<Parameter> Parameters = new List<Parameter>();
        public string Type;
        public int Id;

        public ItemVOParameters(ItemVO item, List<Parameter> parameters){
            Id = item.Id;
            Type = item.ItemType;
            Parameters = parameters;
        }
    }*/
}
